////
//// Created by lfm on 2025/3/15.
////
////虚析构和纯虚析构
////虚析构和纯虚析构的共性：都不能实例化对象，只能作为基类被继承。基类就是通俗的“接口”，派生类就是实现这个接口的具体类。
////虚析构：派生类中有虚函数，则该派生类也必须有虚析构函数，否则编译器会报错。
//// 通俗的讲，虚析构函数是用来释放派生类对象所占用的资源的。
////纯虚析构：派生类中有纯虚函数，则该派生类也必须有纯虚析构函数，否则编译器会报错。
//
//
//#include <iostream>
//#include <string>
//using namespace std;
//class Animal
//{
//public:
//    Animal()
//    {
//        cout << "Animale 的构造函数调用" << endl;
//    }
//    //在这个析构函数加上virtual之前，Cat的析构函数无法调用，因为Animal的析构函数是纯虚函数，不能实例化对象。
//    //加上virtual之后，Cat的析构函数就可以调用了。所以堆区属性的释放问题就解决了。
////    virtual ~Animal()
////    {
////        cout << "Animal 的析构函数调用" << endl;
//    //    }
//    //纯虚函数
//    void virtual speak() = 0;
//    //纯虚析构 需要声明也需要实现
//    //有了纯虚析构之后， 这个类也属于抽象类，不能实例化对象。
//    virtual ~Animal() = 0; //纯虚析构
//};
//
//Animal :: ~Animal() //纯虚析构
//{
//    cout << "Animal 的纯虚析构函数调用" << endl;
//}
//
//class Cat : public Animal
//{
//public:
//    Cat(string name)
//    {
//        cout << "Cat的构造函数调用" << endl;
//        m_Name = new string(name);
//    }
//
//    //利用虚析构可以解决父类指针释放子类对象时不干净问题
//    virtual void speak()
//    {
//        cout <<  *m_Name <<"猫说话" << endl;
//    }
//    ~Cat()
//    {
//        if (m_Name != NULL)
//        {
//            cout << "Cat的析构函数调用" << endl;
//            delete m_Name;
//            m_Name = NULL;
//        }
//    }
//    string * m_Name;
//};
//
//void test01()
//{
//    //问题出在我们用父类的指针指向子类的对象，
//    //父类指针在析构时候不会调用子类中析构函数，
//    //导致子类如果有堆区属性，在父类析构的时候就没有释放，造成内存泄漏。
//    //解决方法：在父类中声明虚析构函数，子类继承虚析构函数，在析构函数中释放堆区属性。
//    Animal * animal = new Cat("Tom");
//    animal->speak();
//    //父类的指针在析构时候不会调用子类中析构函数，
//    //导致子类中有堆区属性
//    delete animal;
//}
//int main()
//{
//    test01();
//    system("pause");
//    return 0;
//}


//总结：
//1.虚析构和纯虚析构就是用来解决通过父类指针指向子类对象时，子类对象没有释放堆区属性的问题。
//2.如果子类没有堆区数据，可以不写为虚析构或纯虚析构
//3.拥有纯虚析构函数的类也属于抽象类，不能实例化对象。只能作为基类被继承。


